/*
 * This file is part of algowala.
 *
 * algowala is copyright (c) 2012 Jagannathan Sampath <algowala@jagernot.com>
 *
 * algowala is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * algowala is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with algowala.  If not, see <http://www.gnu.org/licenses/>.
 *
*/
#include "algo_gl.h"
#include "console.h"
#include "viewwin.h"
#include "ansi_color_codes.h"

#include <iostream>
using namespace std;

void viewport::operator() (int w, int h) {
  if (w != width || h != height) {
    calc (w, h);
    cout << PASS << "+++ viewport: " << width << ' ' << height << " +++" << ENDL;
  }
}

void viewport::calc (int w, int h) {
  width = w;
  height = h;
  xmax = width - 1;
  ymax = height - 1;
  xmax_1 = 1.0 / xmax;
  ymax_1 = 1.0 / ymax;
  handle_factor = handle_radius * 1. / width;  
}

bool viewport::inside (int x, int y) {
  bool xi = (x >= 0) && (x <= xmax);
  bool yi = (y >= 0) && (y <= ymax);
  return (xi && yi);
}

void window::calc_panxy () {
  pan_x = PAN_AMOUNT * width;
  pan_y = PAN_AMOUNT * height;
}

void window::calc_handle_radius () {
  handle_radius = viewport::handle_factor * width;
  handle_radius2 = handle_radius * handle_radius;
}

window::window () : box<double>() {
  width_1 = height_1 = 0;
  aspect_ratio = 0;
}

window::window (double l, double b, double r, double t) {
  set (l, b, r, t);
}

void window::set (double l, double b, double r, double t) {

  operator() (l, b, r, t);

  width_1 = 1.0 / width;
  height_1 = 1.0 / height;

  aspect_ratio = width * height_1;

  calc_panxy ();
  calc_viewwin ();
  calc_handle_radius ();
  window::calc_repeats ();

}

void window::get (double& l, double& b, double& r, double& t) {
  l = left;
  b = bottom;
  r = right;
  t = top;
}

void window::panx (int dir) {
  double dpan = pan_x * dir;
  left = left + dpan;
  right = left + width;
  mousex += dpan;
}

void window::pany (int dir) {
  double dpan = pan_y * dir;
  bottom = bottom + pan_y * dir;
  top = bottom + height;
  mousey += dpan;
}

void window::zoom (int dir) {

  double dw = ZOOM_AMOUNT * width * dir, dh = dw / aspect_ratio, dw2 = dw / 2, dh2 = dh / 2;
  double l = left - dw2;
  double r = right + dw2;
  double b = bottom - dh2;
  double t = top + dh2;
  double w = r - l, h = t - b;
  if ((w > 0) && (h > 0)) {
    set (l, b, r, t);
  }
}

void window::locate_mouse () {
  extern viewport view;
  extern int mousex, mousey;
  view2win (mousex, mousey, window::mousex, window::mousey, view, *this);
  prev_mousex = mousex;
  prev_mousey = mousey;
}

void window::update_mouse () {
  extern int mousex, mousey;
  window::mousex += (mousex - prev_mousex) * vwx;
  window::mousey -= (mousey - prev_mousey) * vwy;
  prev_mousex = mousex;
  prev_mousey = mousey;
}

void window::calc_viewwin () {
  extern viewport view;
  vwx = width / view.xmax;
  vwy = height / view.ymax;
  locate_mouse ();
}

void window::calc_repeats () {
  if (PAN_RATE > 0) PAN_REPEAT = 1. / PAN_RATE;
  if (ZOOM_RATE > 0) ZOOM_REPEAT = 1. / ZOOM_RATE;
}
